package auth

import (
	"github.com/labstack/echo"
	"math/rand"
	"net/http"
	"time"
	// "reflect"
	//"crypto/sha256"
	//"fmt"
	_ "github.com/jinzhu/gorm/dialects/mysql"
	. "model/api"
	. "model/constant"
	"model/db"
)

/**
 *	这里使用 gorm.Model 是为了保持删增记录
 */
type User struct {
	ID       uint   `gorm:"primary_key"`
	Name     string `sql:"type:VARCHAR(50) CHARACTER SET utf8 COLLATE utf8_general_ci"`
	Mobile   int64
	Desc     string `sql:"type:VARCHAR(500) CHARACTER SET utf8 COLLATE utf8_general_ci"`
	Image    string `gorm:column:image`
	Token    string `gorm:column:token`
	Vote     int64
	Modified int64
}

type Ticket struct {
	ID      uint   `gorm:"primary_key"`
	Ip      string `gorm:column:ip`
	Num     int64  `gorm:"default:1"`
	UserID  int64  `gorm:"default:0"`
	Created int64
}

const SALT string = "www.eigenvr.com"

func init() {
	db.Conn.AutoMigrate(&User{}) //自动迁移模式
	db.Conn.AutoMigrate(&Ticket{})
}

func Login(c echo.Context) error {
	conn := db.Conn
	//user_name := c.QueryParam("user_name")
	u := new(User)
	if err := c.Bind(u); err != nil {
		panic(err.Error())
	}

	var user User
	rerr := conn.Where("name = ?", u.Name).First(&user)
	if rerr.RecordNotFound() == false {
		return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE, Reason: NAME_BEEN_REGISTERED})
	}

	rrerr := conn.Where("mobile = ?", u.Mobile).First(&user)
	if rrerr.RecordNotFound() == false {
		return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE, Reason: MOBILE_BEEN_REGISTERED})
	}

	token := CreateToken() //生成一个32位的token
	u.Token = token
	u.Modified = time.Now().Unix()
	u.Vote = 0

	err := conn.Create(&u).Error
	if err == nil {
		if u.ID > 0 {
			type result struct {
				ID    uint
				Token string
			}
			return c.JSON(http.StatusOK, Return{Status: STATUS_SUCCESS, Result: result{ID: u.ID, Token: u.Token}}) //代表注册成功
		}
	}

	return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE, Reason: REGISTER_FAIL})
}

func ShowAll(c echo.Context) error {
	type request struct {
		UserID int64
	}
	r := new(request)
	if err := c.Bind(r); err != nil {
		panic(err.Error())
	}
	conn := db.Conn
	var user []User
	conn.Limit(10).Where("id > ?", r.UserID).Find(&user)
	return c.JSON(http.StatusOK, Return{Status: STATUS_SUCCESS, Result: user})
}

func ShowRank(c echo.Context) error {
	conn := db.Conn
	var user []User
	conn.Find(&user)
	return c.JSON(http.StatusOK, Return{Status: STATUS_SUCCESS, Result: user})
}

func Show(c echo.Context) error {
	type request struct {
		UserID int64
	}
	r := new(request)
	if err := c.Bind(r); err != nil {
		panic(err.Error())
	}
	conn := db.Conn
	var user User
	conn.Where("id = ?", r.UserID).First(&user)
	return c.JSON(http.StatusOK, Return{Status: STATUS_SUCCESS, Result: user})
}

func Vote(c echo.Context) error {
	type request struct {
		UserID int64
	}
	r := new(request)
	if err := c.Bind(r); err != nil {
		panic(err.Error())
	}
	conn := db.Conn

	ip := c.RealIP()
	var ticket Ticket
	rerr := conn.Where("ip = ?", ip).First(&ticket).RecordNotFound()
	if rerr == true {
		ticket.Ip = ip
		ticket.UserID = r.UserID
		ticket.Created = time.Now().Unix()
		conn.Create(&ticket)
	} else {
		if ticket.Num > 10 {
			return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE})
		} else if ticket.Num == 10 {
			ticket.Num = 11
			ticket.UserID = r.UserID
			conn.Save(&ticket)
			var user User
			conn.Where("id = ?", r.UserID).First(&user)
			user.Vote -= 15
			conn.Save(&user)
			return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE})
		} else if ticket.Num >= 5 && time.Now().Unix()-ticket.Created < 300 {
			ticket.Num = 11
			ticket.UserID = r.UserID
			conn.Save(&ticket)
			var user User
			conn.Where("id = ?", r.UserID).First(&user)
			user.Vote -= 8
			conn.Save(&user)
			return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE})
		} else if time.Now().Unix()-ticket.Created < 3 {
			ticket.Num = 11
			ticket.UserID = r.UserID
			conn.Save(&ticket)
			var user User
			conn.Where("id = ?", r.UserID).First(&user)
			user.Vote -= 2
			conn.Save(&user)
			return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE})
		} else {
			ticket.Num += 1
			ticket.UserID = r.UserID
			conn.Save(&ticket)
		}
	}

	var user User
	conn.Where("id = ?", r.UserID).First(&user)
	user.Vote += 1
	conn.Save(&user)

	return c.JSON(http.StatusOK, Return{Status: STATUS_SUCCESS})
}

func CreateToken() string {
	const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
	token_arr := make([]byte, 32)
	for i := range token_arr {
		token_arr[i] = letters[rand.Intn(len(letters))]
	}
	token := string(token_arr) //生成一个32位的token
	return token
}

func TokenVerify(user_id uint, token string) bool {
	conn := db.Conn
	var user User

	err := conn.Where(&User{ID: user_id, Token: token}).First(&user)
	if err.RecordNotFound() == false {
		return true
	} else {
		return false
	}
}

func UserAuth(c echo.Context) error {
	conn := db.Conn
	type request struct {
		UserID uint
		Token  string
	}
	r := new(request)
	if err := c.Bind(r); err != nil {
		panic(err.Error())
	}
	var user User
	if err := conn.Where("id = ? AND token = ?", r.UserID, r.Token).First(&user); err.RecordNotFound() == false {
		return c.JSON(http.StatusOK, Return{Status: STATUS_SUCCESS})
	} else {
		return c.JSON(http.StatusOK, Return{Status: STATUS_FAILURE})
	}

}
